#include <types.h>
#include <sys_config.h>

#include <api/libc/string.h>

#include <api/libtsi/p_search.h>

#include <api/libtsi/si_types.h>
#include <api/libtsi/si_descriptor.h>
#include <api/libtsi/si_section.h>

#include <api/libsi/si_nit.h>
#include <api/libsi/desc_loop_parser.h>

#define SN_DEBUG_LEVEL			0
#if (SN_DEBUG_LEVEL>0)
#include <api/libc/printf.h>
#define SN_PRINTF			libc_printf
#else
#define SN_PRINTF(...)			do{}while(0)
#endif

#if(defined(_LCN_ENABLE_) ||defined(_SERVICE_ATTRIBUTE_ENABLE_))
INT32 si_on_priv_spec_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	n_info->priv_spec = (data[0]<<24)|(data[1]<<16)|(data[2]<<8)|(data[3]);
	
	return SI_SUCCESS;
}
#endif
#ifdef _INVW_JUICE   

#if(defined(SUPPORT_NETWORK_NAME))
INT32 nit_network_name_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;
	UINT8 pos=0;

	while (length >0)
	{		
		n_info->network_provider_name[pos]= data[pos];		
		data += 1;
		length -= 1;
		pos++;
		libc_printf("network_name[%x] : %x \n",pos,data[pos]);
	}
	
	return SI_SUCCESS;
}
#endif

#endif
#if(defined( _MHEG5_ENABLE_) ||defined(_LCN_ENABLE_)||defined(_MHEG5_V20_ENABLE_))
//parse LCN descriptor
INT32 si_on_lcn_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
		return SI_SUCCESS;
	}

	//must follow private data specifier descriptor
//#if(PRIVATE_DATA_SPEC != INVALID_PRIVATE_DATA_SPEC)
//	if(n_info->priv_spec != PRIVATE_DATA_SPEC)
//		return SI_SUCCESS;
//#endif

	//parse lcn loop	
	while (length >= 4)
	{
#ifdef SUPPORT_FRANCE_HD
		UINT16 i;
		for(i=0; i<n_info->s_nr; i++)
		{
			if(n_info->s_info[i].sid == ((data[0]<<8)|data[1]))
				break;
		}

		if(i == n_info->s_nr)
		{
			n_info->s_info[n_info->s_nr].onid = n_info->onid;
			n_info->s_info[n_info->s_nr].tsid = n_info->tsid;
			n_info->s_info[n_info->s_nr].sid = (data[0]<<8)|data[1];
			n_info->s_info[n_info->s_nr].lcn = ((data[2]&0x03)<<8)|data[3];
			SN_PRINTF("LCN[%d]: %d - onid: 0x%X, tsid: 0x%X, sid: 0x%X\n",
						n_info->s_nr,
						n_info->s_info[n_info->s_nr].lcn,
						n_info->s_info[n_info->s_nr].onid,
						n_info->s_info[n_info->s_nr].tsid,
						n_info->s_info[n_info->s_nr].sid
						);
			n_info->s_nr ++;
		}
		else
		{
			n_info->s_info[i].onid = n_info->onid;
			n_info->s_info[i].tsid = n_info->tsid;
			n_info->s_info[i].sid = (data[0]<<8)|data[1];
			n_info->s_info[i].lcn = ((data[2]&0x03)<<8)|data[3];
			SN_PRINTF("LCN[%d]: %d - onid: 0x%X, tsid: 0x%X, sid: 0x%X\n",
						n_info->s_nr,
						n_info->s_info[i].lcn,
						n_info->s_info[i].onid,
						n_info->s_info[i].tsid,
						n_info->s_info[i].sid
						);
		}
			
#else
		n_info->s_info[n_info->s_nr].onid = n_info->onid;
		n_info->s_info[n_info->s_nr].tsid = n_info->tsid;
		n_info->s_info[n_info->s_nr].sid = (data[0]<<8)|data[1];
		n_info->s_info[n_info->s_nr].lcn = ((data[2]&0x03)<<8)|data[3];
		SN_PRINTF("LCN[%d]: %d - onid: 0x%X, tsid: 0x%X, sid: 0x%X\n",
					n_info->s_nr,
					n_info->s_info[n_info->s_nr].lcn,
					n_info->s_info[n_info->s_nr].onid,
					n_info->s_info[n_info->s_nr].tsid,
					n_info->s_info[n_info->s_nr].sid
					);
		n_info->s_nr ++;
#endif			
		if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
			return SI_SUCCESS;
		}

		data += 4;
		length -= 4;
	}
	
	return SI_SUCCESS;
}


// get LCN from NIT
INT32 si_nit_get_info(struct nit_section_info *nsi,
	UINT16 onid, UINT16 tsid, PROG_INFO *pg)
{
	INT32 i;
#ifdef SUPPORT_FRANCE_HD
	for(i=0; i<nsi->s_nr; i++)
	{
		if ((nsi->s_info[i].sid == pg->prog_number)
			&&(nsi->s_info[i].tsid == tsid)
			&&(nsi->s_info[i].onid == onid))
		{
			pg->lcn = nsi->s_info[i].lcn;
			if(nsi->s_info[i].lcn== 0)  //for DTG test SI05
				pg->lcn_true = FALSE;
			else
				pg->lcn_true = TRUE;
			SN_PRINTF("found lcn: %d\n",pg->lcn);
			//return SI_SUCCESS;
		}
	}	
	SN_PRINTF("not found lcn of prog 0x%X!!\n",pg->prog_number);

	for(i=0; i<nsi->hd_nr; i++)
	{
		if ((nsi->hd_info[i].sid == pg->prog_number)
			&&(nsi->hd_info[i].tsid == tsid)
			&&(nsi->hd_info[i].onid == onid))
		{
			pg->hd_lcn = nsi->hd_info[i].hd_lcn;
			if(nsi->hd_info[i].hd_lcn== 0)  //for DTG test SI05
				pg->hd_lcn_true = FALSE;
			else
			{	
				pg->hd_lcn_true = TRUE;
				SN_PRINTF("found hd_lcn: %d,hd_lcn=%x\n",pg->hd_lcn,pg->hd_lcn_true );
			}
			return SI_SUCCESS;
		}
	}	
	SN_PRINTF("not found lcn of prog 0x%X!!\n",pg->prog_number);
#else
	for(i=0; i<nsi->s_nr; i++)
	{
		if ((nsi->s_info[i].sid == pg->prog_number)
			&&(nsi->s_info[i].tsid == tsid)
			&&(nsi->s_info[i].onid == onid))
		{
			pg->lcn = nsi->s_info[i].lcn;
			if(nsi->s_info[i].lcn== 0)  //for DTG test SI05
				pg->lcn_true = FALSE;
			else
				pg->lcn_true = TRUE;
			SN_PRINTF("found lcn: %d\n",pg->lcn);
			return SI_SUCCESS;
		}
	}	
	SN_PRINTF("not found lcn of prog 0x%X!!\n",pg->prog_number);

#endif
	return ERR_FAILUE;
}

#ifdef _ISDBT_ENABLE_

INT32 si_nit_check_prog_info(struct nit_section_info *nsi,
	UINT16 onid, UINT16 tsid, PROG_INFO *pg){
	INT32 i;
	
	for(i=0; i<nsi->s_nr; i++)
	{
		
		if ((nsi->s_info[i].sid == pg->prog_number)
			&&(nsi->s_info[i].tsid == tsid)
			&&(nsi->s_info[i].onid == onid))
		{
			nsi->network_sel[i]=TRUE;	
			return SI_SUCCESS;
			
		}
		else
			nsi->network_sel[i]=FALSE;	
			
	}	
	SN_PRINTF("not found lcn of prog 0x%X!!\n",pg->prog_number);	
	return ERR_FAILUE;
}

static INT8 ews_des_exist = 0;//default:not exist;
void set_ews_des_exist(INT8 exist)
{
	ews_des_exist = exist;
}
INT8 get_ews_des_exist()
{
	return ews_des_exist;
}

INT32 nit_SysManagement_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	//parse lcn loop	
	while (length >0)
	{		
		n_info->system_manage_id= (data[0]<<8)|data[1];
		//libc_printf("smd=%x\n",n_info->system_manage_id);
		data += 2;
		length -= 2;
		if(length<2)
		    break;
	}
	
	return SI_SUCCESS;
}

INT32 nit_Emergency_information_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
#if 1
	struct nit_section_info *n_info = (struct nit_section_info *)priv;
	UINT16 area_code_len=0;
	UINT8 j=0;
	INT16 length_bak=length;

	if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
		return SI_SUCCESS;
	}
	
	while (length_bak >/*>= otherwise it will always true*/ 0)
	{	
		n_info->ews_info[n_info->ews_nr].sid = (data[0]<<8)|data[1];
		n_info->ews_info[n_info->ews_nr].start_end_flag =data[2]&0x01;	

		if(n_info->ews_info[n_info->ews_nr].start_end_flag)
				set_ews_des_exist(1);
		else
				set_ews_des_exist(0);
		
		n_info->ews_info[n_info->ews_nr].signal_level = (data[2]&0x02)>>1;		
		area_code_len= data[3];

		for (j=0;j<area_code_len ;j++)
		{
			n_info->ews_info[n_info->ews_nr].area_code[2*j]=data[4+2*j];//bit[1:5]:state,bit[6:12]:region
                     n_info->ews_info[n_info->ews_nr].area_code[2*j+1]=data[4+2*j+1]&0xf;
			area_code_len-= 2;
			length_bak -= 2;
		}
		
		n_info->ews_nr ++;
	
		if (n_info->ews_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			SN_PRINTF("%s: maximum hd_simul_lcn collected!\n", __FUNCTION__);
			return SI_SUCCESS;
		}

		data += 4;
		length_bak -= 4;
	}
#endif	
	return SI_SUCCESS;
}


#endif

#ifdef SUPPORT_FRANCE_HD
INT32 si_on_HDsimulLCN_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
		return SI_SUCCESS;
	}

	//must follow private data specifier descriptor
#if(PRIVATE_DATA_SPEC != INVALID_PRIVATE_DATA_SPEC)
	if(n_info->priv_spec != PRIVATE_DATA_SPEC)
		return SI_SUCCESS;
#endif

	//parse lcn loop	
	while (length >= 4)
	{
		n_info->hd_info[n_info->hd_nr].onid = n_info->onid;
		n_info->hd_info[n_info->hd_nr].tsid = n_info->tsid;
		n_info->hd_info[n_info->hd_nr].sid = (data[0]<<8)|data[1];
		n_info->hd_info[n_info->hd_nr].hd_lcn = ((data[2]&0x03)<<8)|data[3];
		SN_PRINTF("tag=%x,LCN[%d]: %d - onid: 0x%X, tsid: 0x%X, sid: 0x%X\n",
			              tag,
					n_info->hd_nr,
					n_info->hd_info[n_info->hd_nr].hd_lcn,
					n_info->hd_info[n_info->hd_nr].onid,
					n_info->hd_info[n_info->hd_nr].tsid,
					n_info->hd_info[n_info->hd_nr].sid
					);
		n_info->hd_nr ++;
	
		if (n_info->hd_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			SN_PRINTF("%s: maximum hd_simul_lcn collected!\n", __FUNCTION__);
			return SI_SUCCESS;
		}

		data += 4;
		length -= 4;
	}
	
	return SI_SUCCESS;
}

#endif

#endif

#ifdef _SERVICE_ATTRIBUTE_ENABLE_
INT32 si_on_attribute_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	if (n_info->attrib_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		return SI_SUCCESS;
	}

	//must follow private data specifier descriptor
#if(PRIVATE_DATA_SPEC != INVALID_PRIVATE_DATA_SPEC)
	if(n_info->priv_spec != PRIVATE_DATA_SPEC)
		return SI_SUCCESS;
#endif

	//parse loop	
	while (length >= 3)
	{
		n_info->attrib_info[n_info->attrib_nr].onid = n_info->onid;
		n_info->attrib_info[n_info->attrib_nr].tsid = n_info->tsid;
		n_info->attrib_info[n_info->attrib_nr].sid = (data[0]<<8)|data[1];
		n_info->attrib_info[n_info->attrib_nr].nsf = (data[2] & 0x2)>>1;
		n_info->attrib_info[n_info->attrib_nr].vsf = data[2] & 0x1;

		n_info->attrib_nr ++;
	
		if (n_info->attrib_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			return SI_SUCCESS;
		}

		data += 3;
		length -= 3;
	}
	
	return SI_SUCCESS;
}
#endif

#ifdef _SERVICE_ATTRIBUTE_ENABLE_
INT32 si_service_get_attrib(struct nit_section_info *nsi,
	UINT16 onid, UINT16 tsid, PROG_INFO *pg)
{
	INT32 i;

	for(i=0; i<nsi->attrib_nr; i++)
	{
		if ((nsi->attrib_info[i].sid == pg->prog_number)
			&&(nsi->attrib_info[i].tsid == tsid)
			&&(nsi->attrib_info[i].onid == onid))
		{
			pg->numeric_selection_flag = nsi->attrib_info[i].nsf;
			pg->visible_service_flag = nsi->attrib_info[i].vsf;
			return SI_SUCCESS;
		}
	}

	pg->numeric_selection_flag = 1;
	pg->visible_service_flag = 1;

	return ERR_FAILUE;
}
#endif

#ifdef SUPPORT_FRANCE_HD
INT32 si_on_service_list_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;
	INT16 i;

	if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
		return SI_SUCCESS;
	}

	//parse lcn loop	
	while (length >= 3)
	{
		for(i=0; i<n_info->s_nr; i++)
		{
			if(n_info->s_info[i].sid == ((data[0]<<8)|data[1]))
				break;
		}

		if(i == n_info->s_nr)
		{
			n_info->s_info[n_info->s_nr].onid = n_info->onid;
			n_info->s_info[n_info->s_nr].tsid = n_info->tsid;
			n_info->s_info[n_info->s_nr].sid = (data[0]<<8)|data[1];
			n_info->s_nr ++;
		}
	
		if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
			return SI_SUCCESS;
		}
		data += 3;
		length -= 3;
	}
	
	return SI_SUCCESS;
}

#endif

#if defined(_ISDBT_ENABLE_)
INT32 si_on_TS_information_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	n_info->remote_control_key_id = data[0];
	
	return SI_SUCCESS;
}
#endif


INT32 si_on_extension_descriptor(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
    switch (data[0])    //descriptor_tag_extension
    {
#if defined(DVBT2_SUPPORT)
        case    T2_DELIVERY_SYSTEM_DESCRIPTOR:
            return t2_delivery_system_descriptor_parser(tag, length, data, priv);
            break;
#endif

        default:
            return SI_SUCCESS;
    }
    return SI_SUCCESS;
}

INT32 si_nit_parser(UINT8 *data, INT32 len, struct section_parameter *param)
{
	INT32 i, ret, dloop_len;
	struct network_descriptor *nw_desc;
	struct nit_section_info *n_info = (struct nit_section_info *)param->priv;
	struct transport_stream_info *ts_info;
	if (data == NULL) {
		n_info->xp_nr = 0;
		return SI_SUCCESS;
	}

#if(defined( _MHEG5_ENABLE_) || defined( _MHEG5_V20_ENABLE_) \
	|| defined(NETWORK_ID_ENABLE) || defined(STAR_PROG_SEARCH_NIT_SDT_SUPPORT) || defined(SUPPORT_FRANCE_HD))
	//network_id
	n_info->net_id = (data[3]<<8) | data[4];
    //libc_printf("%s: net id: %X\n",__FUNCTION__,n_info->net_id);
#endif

	/*get nit version*/
	n_info->ext[0].version = (data[5]&0x3E)>>1;
#ifdef SUPPORT_FRANCE_HD
	n_info->version_num = (data[5] &0x3e) >> 1; 
#endif
	
	nw_desc = &((struct nit_section *)data)->network;
	dloop_len = SI_MERGE_HL8(nw_desc->network_descriptor_length);
	
	if (n_info->lp1_nr&&(dloop_len>0)) 
	{
#if (defined(AUTO_OTA) || defined(_ISDBT_ENABLE))
		ret = desc_loop_parser(nw_desc->descriptor, dloop_len, 
			n_info->loop1, n_info->lp1_nr, n_info->p_firstloopinfo.descriptors_parse_stat, n_info);
#else
		ret = desc_loop_parser(nw_desc->descriptor, dloop_len, 
			n_info->loop1, n_info->lp1_nr, NULL, n_info);
#endif
		if (ret != SI_SUCCESS) {
			SN_PRINTF("%s: loop1 parse failure!\n",
				__FUNCTION__);
			return ret;
		}
#ifdef AUTO_OTA
		if(0 == (n_info->p_firstloopinfo.descriptors_parse_stat)&(1<<NIT_LINKAGE_EXIST_BIT))
			set_linkagetype09_exist(0);
#endif
	}
	
	if (n_info->lp2_nr==0) {
		return SI_SUCCESS;
	}
	
	for(i=sizeof(struct nit_section)+dloop_len-4; i<len-4; 
		i += sizeof(struct transport_stream_info)+dloop_len) {
		ts_info = (struct transport_stream_info *)(data+i);
		n_info->tsid = SI_MERGE_UINT16(ts_info->transport_stream_id);
		n_info->onid = SI_MERGE_UINT16(ts_info->original_network_id);
		dloop_len = SI_MERGE_HL8(ts_info->transport_stream_length);
		if (dloop_len>0) {
			ret = desc_loop_parser(ts_info->descriptor,
				dloop_len, n_info->loop2, n_info->lp2_nr, NULL, n_info);
			if (ret != SI_SUCCESS) {
				SN_PRINTF("%s: loop2 parse failure!\n",
					__FUNCTION__);
				return ret;
			}
		}
	}
		
	return SI_SUCCESS;
}

#if 0//(defined( _MHEG5_ENABLE_) ||defined(_LCN_ENABLE_)||defined(_MHEG5_V20_ENABLE_))
//parse LCN descriptor
INT32 si_on_lcn_desc(UINT8 tag, UINT8 length, UINT8 *data, void *priv)
{
	struct nit_section_info *n_info = (struct nit_section_info *)priv;

	if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
	{
		SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
		return SI_SUCCESS;
	}

	//parse lcn loop	
	while (length >= 4)
	{
		n_info->s_info[n_info->s_nr].onid = n_info->onid;
		n_info->s_info[n_info->s_nr].tsid = n_info->tsid;
		n_info->s_info[n_info->s_nr].sid = (data[0]<<8)|data[1];
		n_info->s_info[n_info->s_nr].lcn = ((data[2]&0x03)<<8)|data[3];
		SN_PRINTF("LCN[%d]: %d - onid: 0x%X, tsid: 0x%X, sid: 0x%X\n",
					n_info->s_nr,
					n_info->s_info[n_info->s_nr].lcn,
					n_info->s_info[n_info->s_nr].onid,
					n_info->s_info[n_info->s_nr].tsid,
					n_info->s_info[n_info->s_nr].sid
					);
		n_info->s_nr ++;
	
		if (n_info->s_nr==PSI_MODULE_MAX_NIT_SINFO_NUMBER)
		{
			SN_PRINTF("%s: maximum lcn collected!\n", __FUNCTION__);
			return SI_SUCCESS;
		}

		data += 4;
		length -= 4;
	}
	
	return SI_SUCCESS;
}


// get LCN from NIT
INT32 si_nit_get_info(struct nit_section_info *nsi,
	UINT16 onid, UINT16 tsid, PROG_INFO *pg)
{
	INT32 i;

	for(i=0; i<nsi->s_nr; i++)
	{
		if ((nsi->s_info[i].sid == pg->prog_number)
			&&(nsi->s_info[i].tsid == tsid)
			&&(nsi->s_info[i].onid == onid))
		{
			pg->lcn = nsi->s_info[i].lcn;
			pg->lcn_true = TRUE;
			SN_PRINTF("found lcn: %d\n",pg->lcn);
			return SI_SUCCESS;
		}
	}	
	SN_PRINTF("not found lcn of prog 0x%X!!\n",pg->prog_number);
	return ERR_FAILUE;
}
#endif
#if defined(AUTO_OTA)
extern UINT32 si_get_otaconfig_oui();

/*******************************************************************************
*   Funtion name : get_otaservice_linkage_from_nit()
*   Description:
*       1. search linkage descriptor(linkage type==0x09) in nit.
*       2. psec_list: section list for a complete NIT.
*       3. *plink_exist : if linkage descriptor(linkage_type == 0x09) exist.
*       4. return val: if find matched OUI&service_id, return SUCCESS; else return !SUCCESS
*   Time: 20080420
*******************************************************************************/
INT32 get_otaservice_linkage_from_nit(struct nit_section_info *nit_info, INT8 *plink_exist, UINT16 cur_tsid)
{
	INT32 ret = !SI_SUCCESS;
	INT8 linkagetype09_exist = 0;
	struct NITSSU_INFO *pssuinfo = &nit_info->p_firstloopinfo.ssu_location_info;

	if(0 == linkagetype09_exist)
		linkagetype09_exist = get_linkagetype09_exist();
		
	if(0x09 == pssuinfo->linkage_type)
	{
		if(pssuinfo->des_tsid == cur_tsid)
		{
			if(pssuinfo->OUI == si_get_otaconfig_oui())
			{
				si_set_ota_serviceid(pssuinfo->des_serviceid);
				ret = SUCCESS;
			}
		}
	}
	
	*plink_exist = linkagetype09_exist;
	return ret;
}
#endif

